

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Hashtable;


public class Graph {
	
	private Hashtable<String, Vertex> V;
	private Hashtable<String, Edge> E;
	private boolean directed;
	
	public Graph(Hashtable<String, Vertex> V, Hashtable<String, Edge> E, boolean directed) {
		
		this.V = V;
		this.E = E;
		this.directed = directed;
		
	}
	
	public Vertex getVertex(String key) {
		return V.get(key);
	}
	
	public Edge getEdge(String key) {
		return E.get(key);
	}
	
	public ArrayList<Edge> getEdges() {
		return new ArrayList<Edge>(E.values());
	}
	
	public ArrayList<Vertex> getV() {
		return new ArrayList<Vertex>(V.values());
	}
	
	public boolean isDirected() {
		return directed;
	}
	
	public void print() {
		
		System.out.println("Node\t\tOut nodes\t\tIn nodes");
		for (Vertex v : V.values()) {
			System.out.print(v + "\t\t");
			for (Edge e : v.getOutEdges()) {
				System.out.print(e.getTo() + ", ");
			}
			System.out.print("\t\t");
			for (Edge e : v.getInEdges()) {
				System.out.print(e.getFrom() + ", ");
			}
			System.out.println("");
		}
		
	}
	
	public void printUndirected() {
		
		System.out.println("Node\t\tNeighbours");
		for (Vertex v : V.values()) {
			System.out.print(v + "\t\t");
			for (Vertex n : v.getNeighbours()) {
				System.out.print(n + ", ");
			}
			System.out.println("");
		}
		
	}
	
	public void printEdges() {
		for (Edge e : E.values()) {
			System.out.println(e);
		}
	}
	
	public void generateGraphviz() {
		try {
			
			System.out.print("Generating graph file... ");
			
			//create the graphviz file
			File file = new File("graphs/graph"+Params.RANDOM+".gv");
			FileWriter fw = new FileWriter(file);
			BufferedWriter bw = new BufferedWriter(fw);
			if (isDirected()) bw.write("di");
			bw.write("graph {\n");
			//ordering vertices
			ArrayList<Vertex> lstV = new ArrayList<Vertex>(V.values());
			Collections.sort(lstV, new Comparator<Vertex>() {
				@Override
				public int compare(Vertex v1, Vertex v2) {
					return v1.getId().compareTo(v2.getId());
				}
			});
			for (Vertex v : lstV) {
				bw.write("\t" + v + "\n");
			}
			/*//ordering edges
			ArrayList<Edge> lstE = new ArrayList<Edge>(E.values());
			Collections.sort(lstE, new Comparator<Edge>() {
				@Override
				public int compare(Edge e1, Edge e2) {
					if (e1.getFrom().getId().compareTo(e2.getFrom().getId()) != 0)
						return e1.getFrom().getId().compareTo(e2.getFrom().getId());
					else
						return e1.getTo().getId().compareTo(e2.getTo().getId());
				}
			});*/
			for (Edge e : E.values()) {//lstE
				bw.write("\t" + e + "\n");
			}
			bw.write("}");
			bw.close();
			
			//generate the ps file 
			Process p = Runtime.getRuntime().exec("neato -Tps graphs/"+file.getName()+" -o graphs/graph"+Params.RANDOM+".ps");
			p.waitFor();
			
			System.out.println("done!");
			
		}
		catch (IOException | InterruptedException e) {
			System.err.println("Error on generating graph with Graphviz!");
			e.printStackTrace();
		}
	}

	public void printDegrees() {
		System.out.println("Vertex\t\tDegree of conectivity");
		for (Vertex v : V.values()) {
			System.out.println(v + "\t\t" + v.getNeighbours().size());
		}
	}
	
	public double getAverageVertexDegree() {
		long count = 0;
		for (Vertex v : V.values()) {
			count += v.getNeighbours().size();
		}
		return count/((double)V.size());
	}
	
}
